package com.robert.vesta.rest.netty;
import static io.netty.handler.codec.http.HttpHeaders.is100ContinueExpected;
import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.sf.json.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.intf.IdService;
@Sharable
public class VestaRestNettyServerHandler extends ChannelHandlerAdapter {
private static final String ID = "id";
private static final String VERSION = "version";
private static final String TYPE = "type";
private static final String GENMETHOD = "genMethod";
private static final String MACHINE = "machine";
private static final String TIME = "time";
private static final String SEQ = "seq";
private static final String ACTION_GENID = "/genid";
private static final String ACTION_EXPID = "/expid";
private static final String ACTION_TRANSTIME = "/transtime";
private static final String ACTION_MAKEID = "/makeid";
private static final Log log = LogFactory
.getLog(VestaRestNettyServerHandler.class);
private IdService idService;
public VestaRestNettyServerHandler() {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"spring/vesta-rest-main.xml");
idService = (IdService) ac.getBean("idService");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
if (!(msg instanceof HttpRequest))
return;
HttpRequest req = (HttpRequest) msg;
if (is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
URI uri = new URI(req.getUri());
if (log.isDebugEnabled())
log.debug("request uri==" + uri.getPath());
long id = -1;
long time = -1;
long version = -1;
long type = -1;
long genmethod = -1;
long machine = -1;
long seq = -1;
QueryStringDecoder decoderQuery = new QueryStringDecoder(req.getUri());
Map<String, List<String>> uriAttributes = decoderQuery.parameters();
for (Entry<String, List<String>> attr : uriAttributes.entrySet()) {
for (String attrVal : attr.getValue()) {
if (log.isDebugEnabled())
log.debug("Request Parameter: " + attr.getKey() + '='
+ attrVal);
if (ID.equals(attr.getKey())) {
id = Long.parseLong(attrVal);
} else if (TIME.equals(attr.getKey())) {
time = Long.parseLong(attrVal);
} else if (VERSION.equals(attr.getKey())) {
version = Long.parseLong(attrVal);
} else if (TYPE.equals(attr.getKey())) {
type = Long.parseLong(attrVal);
} else if (GENMETHOD.equals(attr.getKey())) {
genmethod = Long.parseLong(attrVal);
} else if (MACHINE.equals(attr.getKey())) {
machine = Long.parseLong(attrVal);
} else if (SEQ.equals(attr.getKey())) {
seq = Long.parseLong(attrVal);
}
}
}
StringBuffer sbContent = new StringBuffer();
if (ACTION_GENID.equals(uri.getPath())) {
long idl = idService.genId();
if (log.isTraceEnabled())
log.trace("Generated id: " + idl);
sbContent.append(idl);
} else if (ACTION_EXPID.equals(uri.getPath())) {
Id ido = idService.expId(id);
if (log.isTraceEnabled())
log.trace("Explained id: " + ido);
JSONObject jo = JSONObject.fromObject(ido);
sbContent.append(jo);
} else if (ACTION_TRANSTIME.equals(uri.getPath())) {
Date date = idService.transTime(time);
if (log.isTraceEnabled())
log.trace("Time: " + date);
sbContent.append(date);
} else if (ACTION_MAKEID.equals(uri.getPath())) {
long madeId = -1;
if (time == -1 || seq == -1)
sbContent.append("Both time and seq are required.");
else
if (version == -1) {
if (type == -1) {
if (genmethod == -1) {
if (machine == -1) {
madeId = idService.makeId(time, seq);
} else {
madeId = idService.makeId(machine, time, seq);
}
} else {
madeId = idService
.makeId(genmethod, machine, time, seq);
}
} else {
madeId = idService.makeId(type, genmethod, machine, time,
seq);
}
} else {
madeId = idService.makeId(version, type, genmethod, machine,
time, seq);
}
if (log.isTraceEnabled())
log.trace("Id: " + madeId);
sbContent.append(madeId);
} else {
sbContent.append("\r\n");
sbContent.append("Please input right URI:");
sbContent.append("\r\n");
sbContent.append(" Example 1: http://ip:port/genid");
sbContent.append("\r\n");
sbContent.append(" Example 2: http://ip:port/expid?id=?");
sbContent.append("\r\n");
sbContent.append(" Example 3: http://ip:port/transtime?time=?");
sbContent.append("\r\n");
sbContent.append(" Example 4: http://ip:port/makeid?version=?&type=?&genmethod=?&machine=?&time=?&seq=?");
}
if (log.isTraceEnabled())
log.trace("Message body: " + sbContent);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK,
Unpooled.wrappedBuffer(sbContent.toString().getBytes(
Charset.forName("UTF-8"))));
response.headers().set(CONTENT_TYPE, "text/plain");
response.headers().set(CONTENT_LENGTH,
response.content().readableBytes());
boolean keepAlive = isKeepAlive(req);
if (log.isTraceEnabled())
log.trace("Keep Alive: " + keepAlive);
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
ctx.write(response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
if (log.isErrorEnabled())
log.error("HTTP Server Error: ", cause);
ctx.close();
}
}